home *** CD-ROM | disk | FTP | other *** search
- #include "emu.h"
- #include "rmov.h"
- #include "const.h"
-
- extern "C" void shld(void *);
- extern "C" void shrd(void *);
-
- int fprem_do(reg& quot, reg& div, int round) // remainder of st() / st(1)
- {
- int rv;
- int old_cw = control_word;
- control_word &= ~CW_RC;
- control_word |= round;
- int expdif = quot.exp - div.exp;
- if (expdif < 64)
- {
- reg tmp, tmp2;
- r_div(quot, div, tmp);
- long q;
- r_mov(tmp, &q);
- r_mov(&q, tmp);
- r_mul(div, tmp, tmp2);
- r_sub(quot, tmp2, tmp);
- r_mov(tmp, quot);
- rv = q & 7;
- }
- else
- {
- reg tmp, tmp2;
- setcc(SW_C2);
- r_div(st, div, tmp);
- int old_exp = tmp.exp;
- tmp.exp &= 31;
- long q;
- r_mov(tmp, &q);
- r_mov(&q, tmp);
- tmp.exp = old_exp;
- r_mul(div, tmp, tmp2);
- r_sub(quot, tmp2, tmp);
- r_mov(tmp, quot);
- rv = -1;
- }
- control_word = old_cw;
- return rv;;
- }
-
- void fprem()
- {
- if (empty(1))
- return;
- int q = fprem_do(st(), st(1), RC_CHOP);
- if (q == -1)
- setcc(SW_C2);
- else
- {
- int c = 0;
- if (q&4) c |= SW_C3;
- if (q&2) c |= SW_C1;
- if (q&1) c |= SW_C0;
- setcc(c);
- }
- }
-
- void fyl2xp1()
- {
- if (empty())
- return;
- reg frac2, sum, div, term, pow, temp;
- r_mov(st(), frac2);
- r_add(st(), CONST_2, div);
- r_div(frac2, div, sum);
- r_mul(sum, sum, frac2);
- r_mul(sum, st(1), pow);
- for (long i=3; i<15; i+=2)
- {
- r_mul(pow, frac2, temp);
- r_mov(temp, pow);
- r_mov(&i, div);
- r_div(temp, div, term);
- r_add(term, sum, temp);
- r_mov(temp, sum);
- }
- r_div(sum, CONST_LN2, temp);
- temp.exp++;
- r_mov(temp, st(1));
- st().tag = TW_E;
- top++;
- }
-
- void fsqrt()
- {
- if (empty())
- return;
- if (st().tag == TW_Z)
- return;
- if (st().exp == EXP_MAX)
- return;
- if (st().sign == SIGN_NEG)
- return exception(EX_I);
-
- unsigned long long val = *(unsigned long long *)(&st().sigl);
- unsigned long long result = 0;
- unsigned long long side = 0;
- unsigned long long left = 0;
- int digit = 0;
- int i;
- if (st().exp & 1)
- {
- shrd(&val);
- st().exp++;
- }
- int exp = (st().exp - EXP_BIAS - 1)/2 - 64;
- while (!(((long *)&result)[1] & 0x80000000))
- {
- left = (left << 2) + (val >> 62);
- shld(&val);
- shld(&val);
- if (left >= side*2 + 1)
- {
- left -= side*2+1;
- side = (side+1)*2;
- shld(&result);
- result |= 1;
- }
- else
- {
- side *= 2;
- shld(&result);
- }
- exp++;
- }
- st().exp = exp + EXP_BIAS;
- st().sigl = result & 0xffffffff;
- st().sigh = result >> 32;
- st().tag = TW_V;
- }
-
- void fsincos()
- {
- if (empty())
- return;
- int q = fprem_do(st(), CONST_PI2, RC_CHOP);
-
- if (q & 1)
- {
- reg tmp;
- r_sub(CONST_PI2, st(), tmp);
- r_mov(tmp, st());
- }
-
- reg x2, val, rv, tmp, t2;
- reg valc, rvc, tmpc;
- r_mov(st(), val);
- r_mul(st(), val, x2);
- r_mov(val, rv);
- r_mov(CONST_1, valc);
- r_mov(valc, rvc);
-
-
- for (int i=0; i<11; i++)
- {
- val.sign ^= SIGN_POS ^ SIGN_NEG;
- valc.sign ^= SIGN_POS ^ SIGN_NEG;
- r_mul(x2, val, tmp);
- r_mul(x2, valc, tmpc);
- long c = ((i<<1)+2) * ((i<<1)+3);
- r_mov(&c, t2);
- r_div(tmp, t2, val);
- c = ((i<<1)+1) * ((i<<1)+2);
- r_mov(&c, t2);
- r_div(tmpc, t2, valc);
- r_add(val, rv, tmp);
- r_mov(tmp, rv);
- r_add(valc, rvc, tmpc);
- r_mov(tmpc, rvc);
- }
- setcc(0);
-
- if (q & 2)
- rv.sign ^= SIGN_POS ^ SIGN_NEG;
- r_mov(rv, st());
-
- top--;
- register int qq = q & 3;
- if ((qq == 1) || (qq == 2))
- rvc.sign ^= SIGN_POS ^ SIGN_NEG;
- r_mov(rvc, st());
- }
-
- void frndint()
- {
- if (empty())
- return;
- long long tmp;
- if (st().exp > EXP_BIAS+62)
- return;
- r_mov(st(), &tmp);
- r_mov(&tmp, st());
- }
-
- void fscale()
- {
- long scale;
- if (empty(1))
- return;
- r_mov(st(1), &scale);
- st().exp += scale;
- }
-
- void fsin()
- {
- if (empty())
- return;
- int q = fprem_do(st(), CONST_PI2, RC_CHOP);
-
- if (q & 1)
- {
- reg tmp;
- r_sub(CONST_PI2, st(), tmp);
- r_mov(tmp, st());
- }
-
- reg x2, val, rv, tmp, t2;
- r_mov(st(), val);
- r_mul(st(), val, x2);
- r_mov(val, rv);
-
-
- for (int i=0; i<11; i++)
- {
- long c = ((i<<1)+2) * ((i<<1)+3);
- val.sign ^= SIGN_POS ^ SIGN_NEG;
- r_mul(x2, val, tmp);
- r_mov(&c, t2);
- r_div(tmp, t2, val);
- r_add(val, rv, tmp);
- r_mov(tmp, rv);
- }
- setcc(0);
- if (q & 2)
- rv.sign ^= SIGN_POS ^ SIGN_NEG;
- r_mov(rv, st());
- }
-
- void fcos()
- {
- if (empty())
- return;
- int q = fprem_do(st(), CONST_PI2, RC_CHOP);
-
- if (q & 1)
- {
- reg tmp;
- r_sub(CONST_PI2, st(), tmp);
- r_mov(tmp, st());
- }
-
- reg x2, val, rv, tmp, t2;
- r_mov(st(), val);
- r_mul(st(), val, x2);
- r_mov(CONST_1, val);
- r_mov(val, rv);
-
-
- for (int i=0; i<11; i++)
- {
- long c = ((i<<1)+1) * ((i<<1)+2);
- val.sign ^= SIGN_POS ^ SIGN_NEG;
- r_mul(x2, val, tmp);
- r_mov(&c, t2);
- r_div(tmp, t2, val);
- r_add(val, rv, tmp);
- r_mov(tmp, rv);
- }
- setcc(0);
- register int qq = q & 3;
- if ((qq == 1) || (qq == 2))
- rv.sign ^= SIGN_POS ^ SIGN_NEG;
- r_mov(rv, st());
- }
-
- FUNC emu_17_table[] = {
- fprem, fyl2xp1, fsqrt, fsincos, frndint, fscale, fsin, fcos
- };
-
- void emu_17()
- {
- if (modrm > 0277)
- {
- (emu_17_table[modrm&7])();
- }
- else
- {
- // fstcw m16int
- *(short *)get_modrm() = control_word;
- }
- }
-